package Model;

import java.util.ArrayList;

/**
 * This is the class that all Living elements should extend
 */
public abstract class Being {
    // ATTRIBUTE

    private boolean isAlive;
    private boolean isAnimal;
    private int id;
    private int speed;
    private Location location;
    private int visionRadius;
    private Resource resourceBrought;
    protected Activity activity;
    private ArrayList<Location> path;
    private Location targetLocation;

    // CONSTRUCTOR
    public Being(int id, int speed, Location location, int visionRadius, boolean isAnimal) {
        this.id = id;
        this.speed = speed;
        this.location = location;
        this.visionRadius = visionRadius;
        this.isAnimal = isAnimal;
        this.isAlive = true;
        this.resourceBrought = new Resource();
        this.path = new ArrayList<Location>();
    }

    // kind of abstract class methods -- this method from Being is never called
    // BUT called from Villager & Animal class.	
    public abstract void doSpecificAction(Action action, Square actionSquare);

    public abstract Action decideAction(ArrayList<Square> environmentInRadius, ArrayList<Square> directEnvironement);

    public ArrayList<Being> getBeingsInEnvironment(ArrayList<Square> environmentInRadius) {
        int size = environmentInRadius.size();
        ArrayList<Being> res = new ArrayList<Being>();
        for (int i = 0; i < size; i++) {
            if (environmentInRadius.get(i).getBeingReference() != null) {
                res.add(environmentInRadius.get(i).getBeingReference());
            }
        }
        return res;
    }

    public ArrayList<Square> getSquareTypeInEnvironment(ArrayList<Square> environmentInRadius, SquareType squareType) {
        int size = environmentInRadius.size();
        ArrayList<Square> res = new ArrayList<Square>();
        for (int i = 0; i < size; i++) {
            if (environmentInRadius.get(i).getType() == squareType) {
                res.add(environmentInRadius.get(i));
            }
        }
        return res;
    }

    public void moveInDirection(DirectDirection d) {

        switch (d) {
            case North:
                this.location.setYPosition(this.location.getYPosition() - 1);
                break;
            case NorthEast:
                this.location.setXPosition(this.location.getXPosition() + 1);
                this.location.setYPosition(this.location.getYPosition() - 1);
                break;
            case East:
                this.location.setXPosition(this.location.getXPosition() + 1);
                break;
            case SouthEast:
                this.location.setXPosition(this.location.getXPosition() + 1);
                this.location.setYPosition(this.location.getYPosition() + 1);
                break;
            case South:
                this.location.setYPosition(this.location.getYPosition() + 1);
                break;
            case SouthWest:
                this.location.setXPosition(this.location.getXPosition() - 1);
                this.location.setYPosition(this.location.getYPosition() + 1);
                break;
            case West:
                this.location.setXPosition(this.location.getXPosition() - 1);
                break;
            case NorthWest:
                this.location.setXPosition(this.location.getXPosition() - 1);
                this.location.setYPosition(this.location.getYPosition() - 1);
                break;
        }
    }

    public void moveInOppositeDirection(DirectDirection d) {
        switch (d) {
            case North:
                this.location.setYPosition(this.location.getYPosition() + 1);
                break;
            case NorthEast:
                this.location.setXPosition(this.location.getXPosition() - 1);
                this.location.setYPosition(this.location.getYPosition() + 1);
                break;
            case East:
                this.location.setXPosition(this.location.getXPosition() - 1);
                break;
            case SouthEast:
                this.location.setYPosition(this.location.getYPosition() - 1);
                this.location.setXPosition(this.location.getXPosition() - 1);
                break;
            case South:
                this.location.setYPosition(this.location.getYPosition() - 1);
                break;
            case SouthWest:
                this.location.setYPosition(this.location.getYPosition() - 1);
                this.location.setXPosition(this.location.getXPosition() + 1);
                break;
            case West:
                this.location.setXPosition(this.location.getXPosition() + 1);
                break;
            case NorthWest:
                this.location.setYPosition(this.location.getYPosition() + 1);
                this.location.setXPosition(this.location.getXPosition() + 1);
                break;
        }
    }

    public boolean kill() {
        //System.out.println("Trying to kill "+this.getId());
        if(!this.isAlive) {
            return true;
        }
        
        this.isAlive = false;
        if (this.isAnimal) {
            Statistics.setNbDeadAnimals(Statistics.getNbDeadAnimals() + 1);
            switch (((Animal) this).getType()) {
                case Doe:
                    Statistics.setNbDoes(Statistics.getNbDoes() - 1);
                    break;
                case Lion:
                    Statistics.setNbLions(Statistics.getNbLions() - 1);
                    break;
                case Elephant:
                    Statistics.setNbCows(Statistics.getNbCows() - 1);
                    break;

            }
        } else {
            Statistics.setNbDeadVillagers(Statistics.getNbDeadVillagers() + 1);
        }

        return true;
    }

    public void addResourceBrought(Resource res) {
        this.resourceBrought.setAmount(this.resourceBrought.getAmount() + res.getAmount());
    }
    // OWN FUNCTIONS

    public void displayInfoInTerminal() {
        if (this != null) {
            System.out.println("Being-id = " + this.id + " isAnimal = " + this.isAnimal);
            this.location.displayInTerminal();
            this.resourceBrought.displayInTerminal();
        }
    }

    protected DirectDirection getNextPathLocationDirection() {
        DirectDirection nextDirection = DirectDirection.None;
        int pathPosition = 0;

        for (int i = 0; i < this.path.size(); i++) {
            if (this.path.get(i).compare(this.location)) {
                pathPosition = i;
            }
        }

        if (path.get(pathPosition).compare(this.location)) {

            if (pathPosition + 1 < this.path.size() - 1) {
                Location nextLocation = path.get(pathPosition + 1);
                nextDirection = this.location.whatDirectDirectionWith(nextLocation);
            } else {
                //System.out.println("Fin de Path");
                //System.out.println("Being position");
                //path.get(pathPosition).displayInTerminal();
                //System.out.println("Target position");
                //this.getTarget().displayInTerminal();
            }//Else : Fin de path
        } else {
            System.out.println("Path problem...--Being.getNextDirection");
        } //Else : Erreur !! => get new path

        return nextDirection;
    }

    // GETTER - SETTER
    public Resource getResourceBrought() {
        return resourceBrought;
    }

    public int getId() {
        return this.id;
    }

    public int getSpeed() {
        return this.speed;
    }

    public Location getLocation() {
        return this.location;
    }

    public int getVisionRadius() {
        return this.visionRadius;
    }

    public void setResourceBrought(Resource newresourceBrought) {
        this.resourceBrought = newresourceBrought;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setSpeed(int newSpeed) {
        this.speed = newSpeed;
    }

    public void setLocation(Location newLocation) {
        this.location = newLocation;
    }

    public void setVisionRadius(int newVisionRadius) {
        this.visionRadius = newVisionRadius;
    }

    public boolean isAnimal() {
        return isAnimal;
    }

    public boolean isAlive() {
        return isAlive;
    }

    public void setAnimal(boolean isAnimal) {
        this.isAnimal = isAnimal;
    }

    public void setAlive(boolean alive) {
        this.isAlive = alive;
    }

    public Activity getActivity() {
        return activity;
    }

    public void setActivity(Activity activity) {
        this.activity = activity;
    }

    public Location getTarget() {
        return targetLocation;
    }

    public void setPath(ArrayList<Location> path) {
        if (path != null) {
            this.path.clear();
        }
        this.path = path;
    }

    public void setTargetLocation(Location targetLocation) {
        this.targetLocation = targetLocation;
    }

    public ArrayList<Location> getPath() {
        return path;
    }
}
